home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / screen32.lha / screen-3.2b / fileio.c < prev    next >
C/C++ Source or Header  |  1992-06-12  |  52KB  |  2,439 lines

  1. /* Copyright (c) 1991
  2.  *      Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
  3.  *      Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
  4.  * Copyright (c) 1987 Oliver Laumann
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 1, or (at your option)
  9.  * any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program (see the file COPYING); if not, write to the
  18.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  * Noteworthy contributors to screen's design and implementation:
  21.  *    Wayne Davison (davison@borland.com)
  22.  *    Patrick Wolfe (pat@kai.com, kailand!pat)
  23.  *    Bart Schaefer (schaefer@cse.ogi.edu)
  24.  *    Nathan Glasser (nathan@brokaw.lcs.mit.edu)
  25.  *    Larry W. Virden (lwv27%cas.BITNET@CUNYVM.CUNY.Edu)
  26.  *    Howard Chu (hyc@hanauma.jpl.nasa.gov)
  27.  *    Tim MacKenzie (tym@dibbler.cs.monash.edu.au)
  28.  *    Markku Jarvinen (mta@{cc,cs,ee}.tut.fi)
  29.  *    Marc Boucher (marc@CAM.ORG)
  30.  *
  31.  ****************************************************************
  32.  */
  33.  
  34. #ifndef lint
  35.   static char rcs_id[] = "$Id: fileio.c,v 1.3 92/02/04 21:20:45 jnweiger Exp $ FAU";
  36. #endif
  37.  
  38. #if defined(pyr) || defined(MIPS) || defined(GOULD_NP1) || defined(B43)
  39. extern int errno;
  40. #endif
  41. #include <sys/types.h>
  42. #ifndef sgi
  43. # include <sys/file.h>
  44. #endif /* sgi */
  45. #include <sys/stat.h>
  46. #include <fcntl.h>
  47.  
  48. #ifdef BSDI
  49. # include <sys/signal.h>
  50. #endif /* BSDI */
  51.  
  52. #include "config.h"
  53. #include "screen.h"
  54. #include "extern.h"
  55.  
  56. #ifdef _SEQUENT_
  57. # define UTHOST        /* _SEQUENT_ has got ut_find_host() */
  58. #endif
  59.  
  60. #ifndef GETUTENT
  61. # ifdef GETTTYENT
  62. #  include <ttyent.h>
  63. # else
  64. struct ttyent
  65. {
  66.   char *ty_name;
  67. };
  68. static char *tt, *ttnext;
  69. static char ttys[] = "/etc/ttys";
  70. # endif
  71. #endif
  72.  
  73. #if defined(UTMPOK) && defined(GETUTENT) && !defined(SVR4)
  74. # if defined(hpux) /* cruel hpux release 8.0 */
  75. #  define pututline _pututline
  76. # endif /* hpux */
  77. extern struct utmp *getutline(), *pututline();
  78. # if defined(_SEQUENT_)
  79. extern struct utmp *ut_add_user(), *ut_delete_user();
  80. extern char *ut_find_host();
  81. # endif
  82. #endif
  83. #ifdef NETHACK
  84. extern nethackflag;
  85. #endif
  86. int hardcopy_append = 0;
  87. int all_norefresh = 0;
  88.  
  89. extern char *RcFileName, *home, *extra_incap, *extra_outcap;
  90. extern char *BellString, *ActivityString, *ShellProg, *ShellArgs[];
  91. extern char *BufferFile, *PowDetachString, *VisualBellString;
  92. extern int VBellWait, MsgWait, MsgMinWait;
  93. extern struct key ktab[];
  94. extern char Esc, MetaEsc;
  95. extern char *shellaka, SockPath[], *SockNamePtr, *LoginName;
  96. extern int loginflag, allflag, TtyMode, auto_detach;
  97. extern int iflag, rflag, dflag;
  98. extern int default_flow, wrap;
  99. extern HS, termcapHS, use_hardstatus, visual_bell, default_monitor;
  100. extern int default_histheight;
  101. extern int default_startup;
  102. extern int slowpaste;
  103. extern DeadlyMsg, HasWindow;
  104. extern ForeNum, screenwidth, screenheight;
  105. extern char display_tty[];
  106. extern struct win *fore;
  107. extern char screenterm[];
  108. extern int join_with_cr;
  109. extern struct mode OldMode, NewMode;
  110. extern int HasWindow;
  111. extern char mark_key_tab[];
  112. extern int real_uid, eff_uid;
  113. extern int real_gid, eff_gid;
  114.  
  115. #ifdef PASSWORD
  116. int CheckPassword;
  117. char Password[20];
  118. #endif
  119.  
  120. #ifdef COPY_PASTE
  121. extern char *copybuffer;
  122. extern copylen;
  123. #endif
  124.  
  125. static char *CatExtra __P((char *, char *));
  126. static char **SaveArgs __P((int, char **));
  127. static int Parse __P((char *, char *[]));
  128. static char *ParseChar __P((char *, char *));
  129. static void ParseNum __P((int, char *[], int*));
  130. static void ParseOnOff __P((int, char *[], int*));
  131. static void ParseSaveStr __P((int, char *[], char **, char *));
  132. static int IsNum __P((char *, int));
  133. static int IsNumColon __P((char *, int, char *, int));
  134. static slot_t TtyNameSlot __P((char *));
  135.  
  136. #if !defined(GETTTYENT) && !defined(GETUTENT)
  137. static void setttyent __P((void));
  138. static struct ttyent *getttyent __P((void));
  139. #endif
  140.  
  141. /*
  142.  * XXX: system
  143.  */
  144. extern time_t time __P((time_t *));
  145. #if !defined(BSDI) && !defined(SVR4)
  146. extern char *getpass __P((char *));
  147. #endif /* !BSDI && !SVR4 */
  148.  
  149. char *KeyNames[] = 
  150. {
  151.   "screen",
  152.   "select0", "select1", "select2", "select3", "select4",
  153.   "select5", "select6", "select7", "select8", "select9",
  154.   "aka", "clear", "colon", "copy", "detach", "flow",
  155.   "hardcopy", "help", "histnext", "history", "info", "kill", "lastmsg",
  156.   "license",
  157.   "lockscreen", "log", "login", "monitor", "next", "other", "paste",
  158.   "pow_detach", "prev", "quit", "readbuf", "redisplay", "removebuf",
  159.   "reset", "set", "shell", "suspend", "termcap", "time", "vbell",
  160.   "version", "width", "windows", "wrap", "writebuf", "xoff", "xon",
  161.   0,
  162. };
  163.  
  164.  
  165. /* Must be in alpha order !!! */
  166.  
  167. char *RCNames[] =
  168. {
  169.   "activity", "all", "autodetach", "bell", "bind", "bufferfile", "chdir",
  170.   "crlf", "echo", "escape", "flow", "hardcopy_append", "hardstatus", "login", 
  171.   "markkeys", "mode", "monitor", "msgminwait", "msgwait", "nethack", "password",
  172.   "pow_detach_msg", "redraw", "refresh", "screen", "scrollback", "shell", 
  173.   "shellaka", "sleep", "slowpaste", "startup_message", "term", "termcap",
  174.   "terminfo", "vbell", "vbell_msg", "vbellwait", "visualbell",
  175.   "visualbell_msg", "wrap",
  176. };
  177.  
  178. enum RCcases
  179. {
  180.   RC_ACTIVITY,
  181.   RC_ALL,
  182.   RC_AUTODETACH,
  183.   RC_BELL,
  184.   RC_BIND,
  185.   RC_BUFFERFILE,
  186.   RC_CHDIR,
  187.   RC_CRLF,
  188.   RC_ECHO,
  189.   RC_ESCAPE,
  190.   RC_FLOW,
  191.   RC_HARDCOPY_APP,
  192.   RC_HARDSTATUS,
  193.   RC_LOGIN,
  194.   RC_MARKKEYS,
  195.   RC_MODE,
  196.   RC_MONITOR,
  197.   RC_MSGMINWAIT,
  198.   RC_MSGWAIT,
  199.   RC_NETHACK,
  200.   RC_PASSWORD,
  201.   RC_POW_DETACH_MSG,
  202.   RC_REDRAW,
  203.   RC_REFRESH,
  204.   RC_SCREEN,
  205.   RC_SCROLLBACK,
  206.   RC_SHELL,
  207.   RC_SHELLAKA,
  208.   RC_SLEEP,
  209.   RC_SLOWPASTE,
  210.   RC_STARTUP_MESSAGE,
  211.   RC_TERM,
  212.   RC_TERMCAP,
  213.   RC_TERMINFO,
  214.   RC_VBELL,
  215.   RC_VBELL_MSG,
  216.   RC_VBELLWAIT,
  217.   RC_VISUALBELL,
  218.   RC_VISUALBELL_MSG,
  219.   RC_WRAP,
  220.   RC_RCEND
  221. };
  222.  
  223. #ifdef UTMPOK
  224. static utmp, utmpf;
  225. static char UtmpName[] = UTMPFILE;
  226. # ifdef MIPS
  227.   static utmpfappend;
  228. # endif
  229. #endif
  230.  
  231. static FILE *fp = NULL;
  232. static char *rc_name;
  233.  
  234. char *SaveStr(str)
  235. register char *str;
  236. {
  237.   register char *cp;
  238.  
  239.   if ((cp = malloc(strlen(str) + 1)) == NULL)
  240.     Msg_nomem;
  241.   else
  242.     strcpy(cp, str);
  243.   return cp;
  244. }
  245.  
  246. static char *CatExtra(str1, str2)
  247. register char *str1, *str2;
  248. {
  249.   register char *cp;
  250.   register int len1, len2, add_colon;
  251.  
  252.   len1 = strlen(str1);
  253.   if (len1 == 0)
  254.     return(str2);
  255.   add_colon = (str1[len1 - 1] != ':');
  256.   if (str2)
  257.     {
  258.       len2 = strlen(str2);
  259.       if ((cp = realloc(str2, (unsigned) len1 + len2 + add_colon + 1)) == NULL)
  260.     Msg_nomem;
  261.       bcopy(cp, cp + len1 + add_colon, len2 + 1);
  262.     }
  263.   else
  264.     {
  265.       if (len1 == 0)
  266.     return 0;
  267.       if ((cp = malloc((unsigned) len1 + add_colon + 1)) == NULL)
  268.     Msg_nomem;
  269.       cp[len1 + add_colon] = '\0'; 
  270.     }
  271.   bcopy(str1, cp, len1);
  272.   if (add_colon)
  273.     cp[len1] = ':';
  274.  
  275.   return cp;
  276. }
  277.  
  278. static char *findrcfile(rcfile)
  279. char *rcfile;
  280. {
  281.   static char buf[256];
  282.   char *rc, *p;
  283.  
  284.   if (rcfile)
  285.     {
  286.       rc = SaveStr(rcfile);
  287.       debug1("findrcfile: you specified '%s'\n", rcfile);
  288.     }
  289.   else
  290.     {
  291.       debug("findrcfile: you specified nothing...\n");
  292.       if ((p = getenv("ISCREENRC")) != NULL && *p != '\0')
  293.     {
  294.       debug1("  ... but $ISCREENRC has: '%s'\n", p);
  295.       rc = SaveStr(p);
  296.     }
  297.       else if ((p = getenv("SCREENRC")) != NULL && *p != '\0')
  298.     {
  299.       debug1("  ... but $SCREENRC has: '%s'\n", p);
  300.       rc = SaveStr(p);
  301.     }
  302.       else
  303.     {
  304.       debug("  ...nothing in $SCREENRC, defaulting $HOME/.screenrc\n");
  305.       if (strlen(home) > 244)
  306.         Msg(0, "Rc: home too large");
  307.       sprintf(buf, "%s/.iscreenrc", home);
  308.           if (access(buf, R_OK))
  309.         sprintf(buf, "%s/.screenrc", home);
  310.       rc = SaveStr(buf);
  311.     }
  312.     }
  313.   return rc;
  314. }
  315.  
  316. /*
  317.  * this will be called twice:
  318.  * 1) rcfilename = "/etc/screenrc"
  319.  * 2) rcfilename = RcFileName
  320.  */
  321. void
  322. StartRc(rcfilename)
  323. char *rcfilename;
  324. {
  325.   register int argc, len;
  326.   register char *p, *cp;
  327.   char buf[256];
  328.   char *args[MAXARGS], *t;
  329.  
  330.   rc_name = findrcfile(rcfilename);
  331.  
  332.   if ((fp = secfopen(rc_name, "r")) == NULL)
  333.     {
  334.       if (RcFileName && strcmp(RcFileName, rc_name) == 0)
  335.     {
  336.           /*
  337.            * User explicitly gave us that name,
  338.            * this is the only case, where we get angry, if we can't read
  339.            * the file.
  340.            */
  341.       debug3("StartRc: '%s','%s', '%s'\n", RcFileName, rc_name, rcfilename);
  342.           Msg(0, "Unable to open \"%s\".", rc_name);
  343.       /* NOTREACHED */
  344.     }
  345.       debug1("StartRc: '%s' no good. ignored\n", rc_name);
  346.       Free(rc_name);
  347.       rc_name = "";
  348.       return;
  349.     }
  350.   if ((t = getenv("TERM")) == NULL)
  351.     Msg(0, "No TERM in environment.");
  352.   debug1("startrc got termcp:%s\n", t);
  353.   while (fgets(buf, sizeof buf, fp) != NULL)
  354.     {
  355.       if ((p = rindex(buf, '\n')) != NULL)
  356.     *p = '\0';
  357.       if ((argc = Parse(buf, args)) == 0)
  358.     continue;
  359.       if (strcmp(args[0], "echo") == 0)
  360.     {
  361.       if (argc < 2 || (argc == 3 && strcmp(args[1], "-n")) || argc > 3)
  362.         {
  363.           DeadlyMsg = 0;
  364.           Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
  365.         }
  366.       else
  367.         {
  368.           printf((argc == 3) ? "%s" : "%s\r\n", args[argc - 1]);
  369.         }
  370.     }
  371.       else if (strcmp(args[0], "sleep") == 0)
  372.     {
  373.       if (argc != 2)
  374.         {
  375.           DeadlyMsg = 0;
  376.           Msg(0, "%s: sleep: one numeric argument expected.", rc_name);
  377.         }
  378.       else
  379.         sleep(atoi(args[1]));
  380.     }
  381. #ifdef TERMINFO
  382.       else if (strcmp(args[0], "terminfo") == 0)
  383. #else
  384.       else if (strcmp(args[0], "termcap") == 0)
  385. #endif
  386.     {
  387.       if (argc < 3 || argc > 4)
  388.         Msg(0, "%s: %s: incorrect number of arguments.", rc_name, args[0]);
  389.       for (p = args[1]; p && *p; p = cp)
  390.         {
  391.           if ((cp = index(p, '|')) != 0)
  392.         *cp++ = '\0';
  393.           len = strlen(p);
  394.           if (p[len - 1] == '*')
  395.         {
  396.           if (!(len - 1) || !strncmp(p, t, len - 1))
  397.             break;
  398.         }
  399.           else if (!strcmp(p, t))
  400.         break;
  401.         }
  402.       if (!(p && *p))
  403.         continue;
  404.       extra_incap = CatExtra(args[2], extra_incap);
  405.       if (argc == 4)
  406.         extra_outcap = CatExtra(args[3], extra_outcap);
  407.     }
  408.     }
  409.   fclose(fp);
  410.   Free(rc_name);
  411.   rc_name = "";
  412. }
  413.  
  414. static char *
  415. ParseChar(p, cp)
  416. char *p, *cp;
  417. {
  418.   if (*p == '^')
  419.     {
  420.       if (*++p == '?')
  421.         *cp = '\177';
  422.       else if (*p >= '@')
  423.         *cp = Ctrl(*p);
  424.       else
  425.         return 0;
  426.       ++p;
  427.     }
  428.   else if (*p == '\\' && *++p <= '7' && *p >= '0')
  429.     {
  430.       *cp = 0;
  431.       do
  432.         *cp = *cp * 8 + *p - '0';
  433.       while (*++p <= '7' && *p >= '0');
  434.     }
  435.   else
  436.     *cp = *p++;
  437.   return p;
  438. }
  439.  
  440. /*
  441.  * CompileKeys must be called before Markroutine is first used.
  442.  * to initialise the keys with defaults, call CompileKeys(NULL, mark_key_tab);
  443.  *
  444.  * s is an ascii string in a termcap-like syntax. It looks like
  445.  *   "j=u:k=d:l=r:h=l: =.:" and so on...
  446.  * this example rebinds the cursormovement to the keys u (up), d (down),
  447.  * l (left), r (right). placing a mark will now be done with ".".
  448.  */
  449. int CompileKeys(s, array)
  450. char *s, *array;
  451. {
  452.   int i;
  453.   unsigned char key, value;
  454.  
  455.   if (!s || !*s)
  456.     {
  457.       for (i = 0; i < 256; i++)
  458.         array[i] = i;
  459.       return 0;
  460.     }
  461.   while (*s)
  462.     {
  463.       s = ParseChar(s, (char *) &key);
  464.       if (*s != '=')
  465.     return -1;
  466.       do 
  467.     {
  468.           s = ParseChar(++s, (char *) &value);
  469.       array[value] = key;
  470.     }
  471.       while (*s == '=');
  472.       if (!*s) 
  473.     break;
  474.       if (*s++ != ':')
  475.     return -1;
  476.     }
  477.   return 0;
  478. }
  479.  
  480. static char **SaveArgs(argc, argv)
  481. register int argc;
  482. register char **argv;
  483. {
  484.   register char **ap, **pp;
  485.  
  486.   if ((pp = ap = (char **) malloc((unsigned) (argc + 1) * sizeof(char **))) == 0)
  487.     Msg_nomem;
  488. #ifdef notdef
  489.   debug("saveargs:\n"); 
  490. #endif
  491.   while (argc--)
  492.     {
  493.       debug1(" '%s'", *argv);
  494.       *pp++ = SaveStr(*argv++);
  495.     }
  496.   debug("\n");
  497.   *pp = 0;
  498.   return ap;
  499. }
  500.  
  501. void
  502. FinishRc(rcfilename)
  503. char *rcfilename;
  504. {
  505.   /* in FinishRc screen is not yet open, thus Msg() is deadly here.
  506.    */
  507.   char buf[256];
  508.  
  509.   rc_name = findrcfile(rcfilename);
  510.  
  511.   if ((fp = secfopen(rc_name, "r")) == NULL)
  512.     {
  513.       if (RcFileName && strcmp(RcFileName, rc_name) == 0)
  514.     {
  515.           /*
  516.         * User explicitly gave us that name, 
  517.        * this is the only case, where we get angry, if we can't read
  518.        * the file.
  519.        */
  520.         debug3("FinishRc:'%s','%s','%s'\n", RcFileName, rc_name, rcfilename);
  521.           Msg(0, "Unable to open \"%s\".", rc_name);
  522.       /* NOTREACHED */
  523.     }
  524.       debug1("FinishRc: '%s' no good. ignored\n", rc_name);
  525.       Free(rc_name);
  526.       rc_name = "";
  527.       return;
  528.     }
  529.  
  530.   debug("finishrc is going...\n");
  531.   while (fgets(buf, sizeof buf, fp) != NULL)
  532.     {
  533.       RcLine(buf);
  534.     }
  535.   (void) fclose(fp);
  536.   Free(rc_name);
  537.   rc_name = "";
  538. }
  539.  
  540. /*
  541.  * this is a KEY_SET pressed
  542.  */
  543. void
  544. DoSet(argv)
  545. char **argv;
  546. {
  547.   char *p;
  548.   static char buf[256];
  549.  
  550.   p = buf;
  551.   debug("DoSet\n");
  552.   if (!argv || !*argv || !**argv)
  553.     {
  554.       debug("empty DoSet\n");
  555.       sprintf(buf, "set ");
  556.       RcLine(buf);
  557.       return;
  558.     }
  559.   sprintf(p, "set"); p+=3;
  560.   while(*argv && (strlen(buf) + strlen(*argv) < 255))
  561.     {
  562.       sprintf(p, " %s", *argv++);
  563.       p += strlen(p);
  564.     }
  565.   RcLine(buf);
  566. }
  567.  
  568. /*
  569.  *    "$HOST blafoo"       -> "localhost blafoo"
  570.  *    "${HOST}blafoo"          -> "localhostblafoo"
  571.  *    "\$HOST blafoo"     -> "$HOST blafoo"
  572.  *    "\\$HOST blafoo"    -> "\localhost blafoo"
  573.  *    "'$HOST ${HOST}'"    -> "'$HOST ${HOST}'" 
  574.  *    "'\$HOST'"           -> "'\$HOST'"
  575.  *    "\'$HOST' $HOST"       -> "'localhost' $HOST"
  576.  */
  577. static char *expand_env_vars(ss)
  578. char *ss;
  579. {
  580.   static char ebuf[2048];
  581.   register int esize = 2047, quofl = 0;
  582.   register char *e = ebuf;
  583.   register char *s = ss;
  584.   register char *v;
  585.  
  586.   while (*s && *s != '\n' && esize > 0)
  587.     {
  588.       if (*s == '\'')
  589.     quofl ^= 1;
  590.       if (*s == '$' && !quofl)
  591.     {
  592.       char *p, c;
  593.  
  594.       p = ++s;
  595.       if (*s == '{')
  596.         {
  597.           p = ++s;
  598.           while (*p != '}')
  599.             if (*p++ == '\0')
  600.               return ss;
  601.         }
  602.       else
  603.         {
  604.           while (*p != ' ' && *p != '\0' && *p != '\n')
  605.         p++;
  606.         }
  607.       c = *p;
  608.       debug1("exp: c='%c'\n", c);
  609.       *p = '\0';
  610.       if (v = getenv(s)) 
  611.         {
  612.           debug2("exp: $'%s'='%s'\n", s, v);
  613.           while (*v && esize-- > 0)
  614.             *e++ = *v++;
  615.         }
  616.       else 
  617.         debug1("exp: '%s' not env\n", s);
  618.       if ((*p = c) == '}')
  619.         p++;
  620.       s = p;
  621.     }
  622.       else
  623.     {
  624.       if (s[0] == '\\' && !quofl)
  625.         if (s[1] == '$' || (s[1] == '\\' && s[2] == '$') ||
  626.             s[1] == '\'' || (s[1] == '\\' && s[2] == '\''))
  627.           s++;
  628.       *e++ = *s++;
  629.       esize--;
  630.     }
  631.     }
  632.   if (esize <= 0)
  633.     Msg(0, "expand_env_vars: buffer overflow\n");
  634.   *e = '\0';
  635.   return ebuf;
  636. }
  637.  
  638. void
  639. RcLine(ubuf)
  640. char *ubuf;
  641. {
  642.   char *args[MAXARGS];
  643.   register char *buf, *p, **pp, **ap;
  644.   register int argc, setflag;
  645.   int q, qq;
  646.   char key;
  647.   int low, high, mid, x;
  648.  
  649.   buf = expand_env_vars(ubuf); 
  650.  
  651.   ap = args;
  652.  
  653.   if ((p = rindex(buf, '\n')) != NULL)
  654.     *p = '\0';
  655.   if (strncmp("set ", buf, 4) == 0)
  656.     {
  657.       buf += 4;
  658.       setflag = 1;
  659.       debug1("RcLine: '%s' is a set command\n", buf);
  660.     }
  661.   else if (strncmp("se ", buf, 3) == 0)
  662.     {
  663.       buf += 3;
  664.       setflag = 1;
  665.       debug1("RcLine: '%s' is a se command\n", buf);
  666.     }
  667.   else
  668.     {
  669.       setflag = 0;
  670.       debug1("RcLine: '%s'\n", buf);
  671.     }
  672.   if ((argc = Parse(buf, ap)) == 0)
  673.     {
  674.       if (setflag)
  675.     {
  676.       DeadlyMsg = 0;
  677.       Msg(0, "%s: set what?\n", rc_name);
  678.     }
  679.       return;
  680.     }
  681.  
  682.   low = 0;
  683.   high = (int)RC_RCEND - 1;
  684.   while (low <= high)
  685.     {
  686.       mid = (low + high) / 2;
  687.       x = strcmp(ap[0], RCNames[mid]);
  688.       if (x < 0)
  689.         high = mid - 1;
  690.       else if (x > 0)
  691.         low = mid + 1;
  692.       else
  693.         break;
  694.     }
  695.   if (low > high)
  696.     mid = (int)RC_RCEND;
  697.   switch ((enum RCcases) mid)
  698.     {
  699.     case RC_ESCAPE:
  700.       if (argc != 2 || !ParseEscape(ap[1]))
  701.     {
  702.       DeadlyMsg = 0; 
  703.       Msg(0, "%s: two characters required after escape.", rc_name);
  704.       return;
  705.     }
  706.       if (Esc != MetaEsc)
  707.     ktab[Esc].type = KEY_OTHER;
  708.       else
  709.     ktab[Esc].type = KEY_IGNORE;
  710.       return;
  711.     case RC_CHDIR:
  712.       if (setflag)
  713.     break;
  714.       p = argc < 2 ? home : ap[1];
  715.       if (chdir(p) == -1)
  716.     {
  717.       DeadlyMsg = 0; 
  718.       Msg(errno, "%s", p);
  719.     }
  720.       return;
  721.     case RC_SHELL:
  722.       ParseSaveStr(argc, ap, &ShellProg, "shell");
  723.       ShellArgs[0] = ShellProg;
  724.       return;
  725.     case RC_SHELLAKA:
  726.       ParseSaveStr(argc, ap, &shellaka, "shellaka");
  727.       return;
  728.     case RC_SCREEN:
  729.       if (setflag)
  730.     break;
  731.       DoScreen(rc_name, ap + 1);
  732.       return;
  733.     case RC_SLEEP:
  734.     case RC_TERMCAP:
  735.     case RC_TERMINFO:
  736.       return;            /* Already handled */
  737.     case RC_TERM:
  738.       {
  739.         char *tmp = NULL;
  740.  
  741.         ParseSaveStr(argc, ap, &tmp, "term");
  742.         if (!tmp)
  743.           return;
  744.     if (strlen(tmp) >= 20)
  745.       {
  746.         DeadlyMsg = 0;
  747.             Msg(0,"%s: term: argument too long ( < 20)", rc_name);
  748.             Free(tmp);
  749.         return;
  750.           }
  751.         strcpy(screenterm, args[1]);
  752.     Free(tmp);
  753.         debug1("screenterm set to %s\n", screenterm);
  754.         MakeTermcap(0);
  755.         return;    
  756.       }
  757.     case RC_ECHO:
  758.       if (HasWindow && *rc_name == '\0')
  759.     {
  760.       /*
  761.        * user typed ^A:echo... well, echo isn't FinishRc's job,
  762.        * but as he wanted to test us, we show good will
  763.        */
  764.       DeadlyMsg = 0;
  765.       if (argc == 2 || (argc == 3 && !strcmp(ap[1], "-n")))
  766.         Msg(0, "%s", ap[argc - 1]);
  767.       else
  768.          Msg(0, "%s: 'echo [-n] \"string\"' expected.", rc_name);
  769.     }
  770.       return;
  771.     case RC_BELL:
  772.       ParseSaveStr(argc, ap, &BellString, "bell");
  773.       return;
  774.     case RC_BUFFERFILE:
  775.       ParseSaveStr(argc, ap, &BufferFile, "bufferfile");
  776.       return;
  777.     case RC_ACTIVITY:
  778.       ParseSaveStr(argc, ap, &ActivityString, "activity");
  779.       return;
  780.     case RC_POW_DETACH_MSG:
  781.       ParseSaveStr(argc, ap, &PowDetachString, "pow_detach");
  782.       return;
  783.     case RC_LOGIN:
  784. #ifdef UTMPOK
  785.       q = loginflag;
  786.       ParseOnOff(argc, ap, &loginflag);
  787.       if (fore && setflag)
  788.     {
  789.       SlotToggle(loginflag?(1):(-1));
  790.       loginflag = q;
  791.     }
  792. #endif
  793.       return;
  794.     case RC_FLOW:
  795.       if (argc == 3 && ap[2][0] == 'i')
  796.     {
  797.       iflag = 1;
  798.       argc--;
  799.     }
  800.       if (argc == 2 && ap[1][0] == 'a')
  801.     default_flow = FLOW_AUTOFLAG;
  802.       else
  803.     ParseOnOff(argc, ap, &default_flow);
  804.       return;
  805.     case RC_WRAP:
  806.       ParseOnOff(argc, ap, &wrap);
  807.       return;
  808.     case RC_HARDSTATUS:
  809.       ParseOnOff(argc, ap, &use_hardstatus);
  810.       if (use_hardstatus)
  811.     HS = termcapHS;
  812.       else
  813.     HS = 0;
  814.       return;
  815.     case RC_MONITOR:
  816.     {
  817.       int f; 
  818.  
  819.       ParseOnOff(argc, ap, &f);
  820.       if (fore && setflag)
  821.         fore->monitor = (f == 0) ? MON_OFF : MON_ON;
  822.       else
  823.         default_monitor = (f == 0) ? MON_OFF : MON_ON;
  824.     }
  825.       return;
  826.     case RC_REDRAW:
  827.     case RC_REFRESH:
  828.     {
  829.       int r;
  830.  
  831.       ParseOnOff(argc, ap, &r);
  832.       if (fore && setflag)
  833.         fore->norefresh = (r) ? 0 : 1;
  834.       else
  835.         {
  836.           all_norefresh = (r) ? 0 : 1;
  837.           if (all_norefresh)
  838.             Msg(0, "No refresh on window change!\n");
  839.           else
  840.             Msg(0, "Window specific refresh\n");
  841.         }
  842.     }
  843.       return;
  844.     case RC_VBELL:
  845.     case RC_VISUALBELL:
  846.       ParseOnOff(argc, ap, &visual_bell);
  847.       return;
  848.     case RC_VBELLWAIT:
  849.       ParseNum(argc, ap, &VBellWait);
  850.       if (fore && rc_name[0] == '\0')
  851.         Msg(0, "vbellwait set to %d seconds", VBellWait);
  852.       return;
  853.     case RC_MSGWAIT:
  854.       ParseNum(argc, ap, &MsgWait);
  855.       if (fore && rc_name[0] == '\0')
  856.         Msg(0, "msgwait set to %d seconds", MsgWait);
  857.       return;
  858.     case RC_MSGMINWAIT:
  859.       ParseNum(argc, ap, &MsgMinWait);
  860.       if (fore && rc_name[0] == '\0')
  861.         Msg(0, "msgminwait set to %d seconds", MsgMinWait);
  862.       return;
  863.     case RC_SCROLLBACK:
  864.       if (fore && setflag)
  865.     {
  866.       int i;
  867.  
  868.       ParseNum(argc, ap, &i);
  869.       ChangeScrollback(fore, i, fore->width);
  870.       if (fore && rc_name[0] == '\0')
  871.         Msg(0, "scrollback set to %d", fore->histheight);
  872.     }
  873.       else
  874.     ParseNum(argc, ap, &default_histheight);
  875.       return;
  876.     case RC_SLOWPASTE:
  877.       ParseNum(argc, ap, &slowpaste);
  878.       if (fore && rc_name[0] == '\0')
  879.     Msg(0, "slowpaste set to %d milliseconds", slowpaste);
  880.       return;
  881.     case RC_MARKKEYS:
  882.       {
  883.         char *tmp = NULL;
  884.  
  885.         ParseSaveStr(argc, ap, &tmp, "markkeys");
  886.         if (CompileKeys(ap[1], mark_key_tab))
  887.       {
  888.         DeadlyMsg = 0;
  889.         Msg(0, "%s: markkeys: syntax error.", rc_name);
  890.         Free(tmp);
  891.         return;
  892.       }
  893.         debug1("markkeys %s\n", ap[1]);
  894.         Free(tmp);
  895.         return;
  896.       }
  897. #ifdef NETHACK
  898.     case RC_NETHACK:
  899.       ParseOnOff(argc, ap, &nethackflag);
  900.       return;
  901. #endif
  902.     case RC_HARDCOPY_APP:
  903.       ParseOnOff(argc, ap, &hardcopy_append);
  904.       return;
  905.     case RC_VBELL_MSG:
  906.     case RC_VISUALBELL_MSG:
  907.       ParseSaveStr(argc, ap, &VisualBellString, "vbell_msg");
  908.       debug1(" new vbellstr '%s'\n", VisualBellString);
  909.       return;
  910.     case RC_MODE:
  911.       if (argc != 2)
  912.     {
  913.       DeadlyMsg = 0; 
  914.       Msg(0, "%s: mode: one argument required.", rc_name);
  915.       return;
  916.     }
  917.       if (!IsNum(ap[1], 7))
  918.     {
  919.       DeadlyMsg = 0; 
  920.       Msg(0, "%s: mode: octal number expected.", rc_name);
  921.       return;
  922.     }
  923.       (void) sscanf(ap[1], "%o", &TtyMode);
  924.       return;
  925.     case RC_CRLF:
  926.       ParseOnOff(argc, ap, &join_with_cr);
  927.       return;
  928.     case RC_AUTODETACH:
  929.       ParseOnOff(argc, ap, &auto_detach);
  930.       return;
  931.     case RC_STARTUP_MESSAGE:
  932.       ParseOnOff(argc, ap, &default_startup);
  933.       return;
  934. #ifdef PASSWORD
  935.     case RC_PASSWORD:
  936.       CheckPassword = 1;
  937.       if (argc >= 2)
  938.     {
  939.       strncpy(Password, ap[1], sizeof Password);
  940.       if (!strcmp(Password, "none"))
  941.         CheckPassword = 0;
  942.     }
  943.       else
  944.     {
  945.       char *mstr = 0;
  946.       int msleep = 0, st;
  947.           char salt[2];
  948.  
  949. #ifdef POSIX
  950.       if (HasWindow)
  951.         {
  952.           Msg(0, "Cannot ask for password on POSIX systems");
  953.           return;
  954.         }
  955. #endif
  956.       /* there is a clear screen sequence in the buffer. */
  957.       fflush(stdout);
  958.       if (HasWindow)
  959.         {
  960.               ClearDisplay();
  961.           SetTTY(0, &OldMode);
  962.         }
  963.       strncpy(Password, getpass("New screen password:"),
  964.           sizeof(Password));
  965.       if (strcmp(Password, getpass("Retype new password:")))
  966.         {
  967. #ifdef NETHACK
  968.               if (nethackflag)
  969.             mstr = "[ Passwords don't match - your armor crumbles away ]";
  970.           else
  971. #endif
  972.           mstr = "[ Passwords don't match - checking turned off ]";
  973.           msleep = 1;
  974.           CheckPassword = 0;
  975.         }
  976.       if (Password[0] == '\0')
  977.         {
  978.           CheckPassword = 0;
  979.           mstr = "[ No password - no secure ]";
  980.           msleep = 1;
  981.         }
  982.       for (st=0; st<2; st++)
  983.             salt[st] = 'A' + (int)((time(0) >> 6*st) % 26);
  984.       strncpy(Password, crypt(Password, salt), sizeof(Password));
  985.       if (CheckPassword)
  986.         {
  987. #ifdef COPY_PASTE
  988.           if (copybuffer)
  989.  
  990.         Free(copybuffer);
  991.           copylen = strlen(Password);
  992.           if ((copybuffer = (char *) malloc(copylen+1)) == NULL)
  993.         {
  994.           Msg_nomem;
  995.           return;
  996.         }
  997.           strcpy(copybuffer, Password);
  998.           mstr = "[ Password moved into copybuffer ]";
  999.           msleep = 1;
  1000. #else                /* COPY_PASTE */
  1001.           mstr = "[ Crypted password is \"%s\" ]";
  1002.           msleep = 5;
  1003. #endif                /* COPY_PASTE */
  1004.         }
  1005.           if (HasWindow)
  1006.         {
  1007.           SetTTY(0, &NewMode);
  1008.           Activate(0); /* Redraw */
  1009.           if (mstr)
  1010.             {
  1011.               Msg(0, mstr, Password);
  1012.             }
  1013.         }
  1014.           else
  1015.         {
  1016.           if (mstr)
  1017.             {
  1018.               printf(mstr, Password);
  1019.               putchar('\n');
  1020.               sleep(msleep);
  1021.             }
  1022.               ClearDisplay();
  1023.         }
  1024.     }
  1025.       debug1("finishrc: our password is: --%s%-- \n", Password);
  1026.       return;
  1027. #endif                /* PASSWORD */
  1028.     case RC_ALL:
  1029.       if (!setflag || !HasWindow || *rc_name)
  1030.         break;
  1031.       display_help();
  1032.       return;
  1033.     case RC_BIND:
  1034.       if (setflag)
  1035.     break;
  1036.       p = ap[1];
  1037.       if (argc < 2 || *p == '\0')
  1038.     {
  1039.       DeadlyMsg = 0; 
  1040.       Msg(0, "%s: key expected after bind.", rc_name);
  1041.       return;
  1042.     }
  1043.       if ((p = ParseChar(p, &key)) == NULL || *p)
  1044.     {
  1045.       DeadlyMsg = 0; 
  1046.       Msg(0, "%s: bind: character, ^x, or (octal) \\032 expected.",
  1047.           rc_name);
  1048.       return;
  1049.     }
  1050.       if (ktab[key].type != KEY_IGNORE)
  1051.     {
  1052.       ktab[key].type = KEY_IGNORE;
  1053.       if ((pp = ktab[key].args) != NULL)
  1054.         {
  1055.           for (; *pp; pp++)
  1056.         Free(*pp);
  1057.           Free(ktab[key].args);
  1058.         }
  1059.     }
  1060.       if (argc > 2)
  1061.     {
  1062.       for (pp = KeyNames; *pp; ++pp)
  1063.         if (strcmp(ap[2], *pp) == 0)
  1064.           break;
  1065.       if (*pp)
  1066.         {
  1067.           ktab[key].type = (enum keytype) (pp - KeyNames + 1);
  1068.           if (argc > 3)
  1069.         {
  1070.           ktab[key].args = SaveArgs(argc - 3, ap + 3);
  1071.         }
  1072.           else
  1073.         ktab[key].args = NULL;
  1074.         }
  1075.       else
  1076.         {
  1077.           ktab[key].type = KEY_CREATE;
  1078.           ktab[key].args = SaveArgs(argc - 2, ap + 2);
  1079.         }
  1080.     }
  1081.       return;
  1082.     case RC_RCEND:
  1083.     default:
  1084.     {
  1085.       char ibuf[3];
  1086.       /*
  1087.        * now we are user-friendly: 
  1088.        * if anyone typed a key name like "help" or "next" ...
  1089.        * we did not match anything above. so look in the KeyNames table.
  1090.        */
  1091.       debug1("--ap[0] %s\n", ap[0]);
  1092.       for (pp = KeyNames; *pp; ++pp)
  1093.         if (strcmp(ap[0], *pp) == 0)
  1094.         break;
  1095.       if (*pp == 0)
  1096.         break;
  1097.  
  1098.       ibuf[0] = Esc;
  1099.       ibuf[1] = pp - KeyNames +1;
  1100.       debug1("RcLine: it was a keyname: '%s'\n", *pp);
  1101.       q = 2; qq = 0;
  1102.       if (HasWindow)
  1103.         ProcessInput(ibuf, &q, (char *)0, &qq, 0);
  1104.       else
  1105.         {
  1106.           DeadlyMsg = 0; 
  1107.           Msg(0, "%s: Key '%s' has no effect while no window open...\n",
  1108.               rc_name, ap[0]);
  1109.         }
  1110.     }
  1111.       return;
  1112.     }
  1113.   DeadlyMsg = 0; 
  1114.   Msg(0, "%s: unknown %skeyword \"%s\"", rc_name, 
  1115.       setflag?"'set' ":"", ap[0]);
  1116. }
  1117.  
  1118. static int 
  1119. Parse(buf, args)
  1120. char *buf, **args;
  1121. {
  1122.   register char *p = buf, **ap = args;
  1123.   register int delim, argc;
  1124.  
  1125.   argc = 0;
  1126.   for (;;)
  1127.     {
  1128.       while (*p && (*p == ' ' || *p == '\t'))
  1129.     ++p;
  1130.       if (*p == '\0' || *p == '#')
  1131.     {
  1132.       *p = '\0';
  1133.       return argc;
  1134.     }
  1135.       if (argc > MAXARGS - 1)
  1136.     Msg(0, "%s: too many tokens.", rc_name);
  1137.       delim = 0;
  1138.       if (*p == '"' || *p == '\'')
  1139.     delim = *p++;
  1140.       argc++;
  1141.       *ap = p;
  1142.       *++ap = 0;
  1143.       while (*p && !(delim ? *p == delim : (*p == ' ' || *p == '\t')))
  1144.     ++p;
  1145.       if (*p == '\0')
  1146.     {
  1147.       if (delim)
  1148.         {
  1149.           DeadlyMsg = 0;
  1150.           Msg(0, "%s: Missing quote.", rc_name);
  1151.           return 0;
  1152.     }
  1153.       return argc;
  1154.     }
  1155.       *p++ = '\0';
  1156.     }
  1157. }
  1158.  
  1159. int 
  1160. ParseEscape(p)
  1161. char *p;
  1162. {
  1163.   if ((p = ParseChar(p, &Esc)) == NULL ||
  1164.       (p = ParseChar(p, &MetaEsc)) == NULL || *p)
  1165.     return 0;
  1166.   return 1;
  1167. }
  1168.  
  1169. static void
  1170. ParseNum(argc, ap, var)
  1171. int argc;
  1172. char *ap[];
  1173. int *var;
  1174. {
  1175.   int i;
  1176.   char *p;
  1177.  
  1178.   if (argc == 2 && ap[1][0] != '\0')
  1179.     {
  1180.       i = 0; 
  1181.       p = ap[1];
  1182.       while (*p)
  1183.     {
  1184.       if (*p >= '0' && *p <= '9')
  1185.         i = 10 * i + (*p - '0');
  1186.       else
  1187.         {
  1188.           DeadlyMsg = 0;
  1189.           Msg(0, "%s: %s: invalid argument. Give numeric argument",
  1190.           rc_name, ap[0]);
  1191.           return;
  1192.         }    
  1193.       p++;
  1194.     }
  1195.     }
  1196.   else
  1197.     {
  1198.       DeadlyMsg = 0;
  1199.       Msg(0, "%s: %s: invalid argument. Give one argument",
  1200.           rc_name, ap[0]);
  1201.       return;
  1202.     }
  1203.   debug1("ParseNum got %d\n", i);
  1204.   *var = i;
  1205. }
  1206.  
  1207. static void
  1208. ParseSaveStr(argc, ap, var, title)
  1209. int argc;
  1210. char *ap[];
  1211. char **var;
  1212. char *title;
  1213. {
  1214.   if (argc != 2)
  1215.     {
  1216.       DeadlyMsg = 0;
  1217.       Msg(0, "%s: %s: one argument required.", rc_name, title);
  1218.       return;
  1219.     }
  1220.   if (*var)
  1221.     Free(*var);
  1222.   *var = SaveStr(ap[1]);
  1223.   return;
  1224. }
  1225.  
  1226. static void
  1227. ParseOnOff(argc, ap, var)
  1228. int argc;
  1229. char *ap[];
  1230. int *var;
  1231. {
  1232.   register int num = -1;
  1233.  
  1234.   if (argc == 2 && ap[1][0] == 'o')
  1235.     {
  1236.       if (ap[1][1] == 'f')
  1237.     num = 0;
  1238.       else if (ap[1][1] == 'n')
  1239.     num = 1;
  1240.     }
  1241.   if (num < 0)
  1242.     {
  1243.       DeadlyMsg = 0;
  1244.       Msg(0, "%s: %s: invalid argument. Give 'on' or 'off'", rc_name, ap[0]);
  1245.       return;
  1246.     }
  1247.   *var = num;
  1248. }
  1249.  
  1250.  
  1251. static int IsNum(s, base)
  1252. register char *s;
  1253. register int base;
  1254. {
  1255.   for (base += '0'; *s; ++s)
  1256.     if (*s < '0' || *s > base)
  1257.       return 0;
  1258.   return 1;
  1259. }
  1260.  
  1261. static int IsNumColon(s, base, p, psize)
  1262. int base, psize;
  1263. char *s, *p;
  1264. {
  1265.   char *q;
  1266.   if ((q = rindex(s, ':')) != NULL)
  1267.     {
  1268.       strncpy(p, q + 1, psize - 1);
  1269.       p[psize - 1] = '\0';
  1270.       *q = '\0';
  1271.     }
  1272.   else
  1273.     *p = '\0';
  1274.   return IsNum(s, base);
  1275. }
  1276.  
  1277. void
  1278. SlotToggle(how)
  1279. int how;
  1280. /*
  1281.  * how = 0    real toggle mode
  1282.  * how > 0    do try to set a utmp slot.
  1283.  * how < 0    try to withdraw a utmp slot
  1284.  *
  1285.  * slot = -1    window not logged in.
  1286.  * slot = 0     window not logged in, but should be logged in. 
  1287.  *              (unable to write utmp, or detached).
  1288.  */
  1289. {
  1290.   debug1("SlotToggle %d\n", how);
  1291.   if (how == 0)
  1292.     how = (fore->slot == (slot_t) -1)?(1):(-1);
  1293.     /* 
  1294.      * slot 0 or active -> we try to log out.
  1295.      * slot -1          -> we try to log in.
  1296.      */
  1297. #ifdef UTMPOK
  1298.   if (how > 0)
  1299.     {
  1300.       debug(" try to log in\n");
  1301.       if ((fore->slot == (slot_t) -1) || (fore->slot == (slot_t) 0))
  1302.     {
  1303. #ifdef USRLIMIT
  1304.           if (CountUsers() >= USRLIMIT)
  1305.             Msg(0, "User limit reached.");
  1306.           else
  1307. #endif
  1308.             {
  1309.               if (SetUtmp(fore, ForeNum) == 0)
  1310.                 Msg(0, "This window is now logged in.");
  1311.               else
  1312.                 Msg(0, "This window should now be logged in.");
  1313.             }
  1314.     }
  1315.       else
  1316.     Msg(0, "This window is already logged in.");
  1317.     }
  1318.   else if (how < 0)
  1319.     {
  1320.       debug(" try to log out\n");
  1321.       if (fore->slot == (slot_t) -1)
  1322.     Msg(0, "This window is already logged out\n");
  1323.       else if (fore->slot == (slot_t) 0)
  1324.     {
  1325.       debug("What a relief! In fact, it was not logged in\n");
  1326.       Msg(0, "This window is not logged in.");
  1327.       fore->slot = (slot_t) -1;
  1328.     }
  1329.       else
  1330.     {
  1331.       RemoveUtmp(fore);
  1332.       if (fore->slot != (slot_t) -1)
  1333.         Msg(0, "What? Cannot remove Utmp slot?");
  1334.       else
  1335.         Msg(0, "This window is no longer logged in.");
  1336.     }
  1337.     }
  1338. #else    /* !UTMPOK */
  1339.   Msg(0, "Unable to modify %s.\n", UTMPFILE);
  1340. #endif
  1341. }
  1342.  
  1343. void
  1344. DoScreen(fn, av)
  1345. char *fn, **av;
  1346. {
  1347.   register int flowflag, num, lflag = loginflag, aflag = 0;
  1348.   register char *aka = NULL;
  1349.   register int histheight = default_histheight;
  1350.   char buf[20];
  1351.   char termbuf[25];
  1352.   char *termp;
  1353.   char *args[2];
  1354.  
  1355.   flowflag = default_flow;
  1356.   termbuf[0] = '\0';
  1357.   termp = NULL;
  1358.   while (av && *av && av[0][0] == '-')
  1359.     {
  1360.       switch (av[0][1])
  1361.     {
  1362.     case 'f':
  1363.       switch (av[0][2])
  1364.         {
  1365.         case 'n':
  1366.         case '0':
  1367.           flowflag = FLOW_NOW * 0;
  1368.           break;
  1369.         case 'y':
  1370.         case '1':
  1371.         case '\0':
  1372.           flowflag = FLOW_NOW * 1;
  1373.           break;
  1374.         case 'a':
  1375.           flowflag = FLOW_AUTOFLAG;
  1376.           break;
  1377.         default:
  1378.           break;
  1379.         }
  1380.       break;
  1381.     case 'k':
  1382.     case 't':
  1383.       if (av[0][2])
  1384.         aka = &av[0][2];
  1385.       else if (*++av)
  1386.         aka = *av;
  1387.       else
  1388.         --av;
  1389.       break;
  1390.     case 'T':
  1391.       if (av[0][2])
  1392.         termp = &av[0][2];
  1393.       else if (*++av)
  1394.         termp = *av;
  1395.       else
  1396.         --av;
  1397.       break;
  1398.     case 'h':
  1399.       if (av[0][2])
  1400.         histheight = atoi(av[0] + 2);
  1401.       else if (*++av)
  1402.         histheight = atoi(*av);
  1403.       else 
  1404.         --av;
  1405.       break;
  1406.     case 'l':
  1407.       switch (av[0][2])
  1408.         {
  1409.         case 'n':
  1410.         case '0':
  1411.           lflag = 0;
  1412.           break;
  1413.         case 'y':
  1414.         case '1':
  1415.         case '\0':
  1416.           lflag = 1;
  1417.           break;
  1418.         default:
  1419.           break;
  1420.         }
  1421.       break;
  1422.     case 'a':
  1423.       aflag = 1;
  1424.       break;
  1425.     default:
  1426.       Msg(0, "%s: screen: invalid option -%c.", fn, av[0][1]);
  1427.       break;
  1428.     }
  1429.       ++av;
  1430.     }
  1431.   num = 0;
  1432.   if (av && *av && IsNumColon(*av, 10, buf, sizeof(buf)))
  1433.     {
  1434.       if (*buf != '\0')
  1435.     aka = buf;
  1436.       num = atoi(*av);
  1437.       if (num < 0 || num > MAXWIN - 1)
  1438.     {
  1439.       Msg(0, "%s: illegal screen number %d.", fn, num);
  1440.       num = 0;
  1441.     }
  1442.       ++av;
  1443.     }
  1444.   if (!av || !*av)
  1445.     {
  1446.       av = args;
  1447.       av[0] = ShellProg;
  1448.       av[1] = NULL;
  1449.       if (!aka)
  1450.     aka = shellaka;
  1451.     }
  1452.   MakeWindow(aka, av, aflag, flowflag, num, (char *) 0, lflag, histheight, termp);
  1453. }
  1454.  
  1455. void
  1456. WriteFile(dump)
  1457. int dump;
  1458. {
  1459.   /* dump==0:    create .termcap,
  1460.    * dump==1:    hardcopy,
  1461.    * #ifdef COPY_PASTE
  1462.    * dump==2:    BUFFERFILE
  1463.    * #endif COPY_PASTE 
  1464.    */
  1465.   register int i, j, k;
  1466.   register char *p;
  1467.   register FILE *f;
  1468.   char fn[1024];
  1469.   char *mode = "w";
  1470.  
  1471.   switch (dump)
  1472.     {
  1473.     case DUMP_TERMCAP:
  1474.       i = SockNamePtr - SockPath;
  1475.       strncpy(fn, SockPath, i);
  1476.       strcpy(fn + i, ".termcap");
  1477.       break;
  1478.     case DUMP_HARDCOPY:
  1479.       sprintf(fn, "hardcopy.%d", ForeNum);
  1480.       if (hardcopy_append && !access(fn, W_OK))
  1481.     mode = "a";
  1482.       break;
  1483.     case DUMP_EXCHANGE:
  1484.       sprintf(fn, "%s", BufferFile);
  1485.       umask(0);
  1486.       break;
  1487.     }
  1488.  
  1489.   debug2("WriteFile(%d) %s\n", dump, fn);
  1490.   if (UserContext() > 0)
  1491.     {
  1492.       debug("Writefile: usercontext\n");
  1493.       if ((f = fopen(fn, mode)) == NULL)
  1494.     {
  1495.       debug2("WriteFile: fopen(%s,\"%s\") failed\n", fn, mode);
  1496.       UserReturn(0);
  1497.     }
  1498.       else
  1499.     {
  1500.       switch (dump)
  1501.         {
  1502.         case DUMP_HARDCOPY:
  1503.           if (*mode == 'a')
  1504.         {
  1505.           putc('>', f);
  1506.           for (j = screenwidth - 2; j > 0; j--)
  1507.             putc('=', f);
  1508.           fputs("<\n", f);
  1509.         }
  1510.           for (i = 0; i < screenheight; ++i)
  1511.         {
  1512.           p = fore->image[i];
  1513.           for (k = screenwidth - 1; k >= 0 && p[k] == ' '; --k)
  1514.             ;
  1515.           for (j = 0; j <= k; ++j)
  1516.             putc(p[j], f);
  1517.           putc('\n', f);
  1518.         }
  1519.           break;
  1520.         case DUMP_TERMCAP:
  1521.           if ((p = index(MakeTermcap(fore->aflag), '=')) != NULL)
  1522.         {
  1523.           fputs(++p, f);
  1524.           putc('\n', f);
  1525.         }
  1526.           break;
  1527. #ifdef COPY_PASTE
  1528.         case DUMP_EXCHANGE:
  1529.           p = copybuffer;
  1530.           for (i = 0; i < copylen; i++)
  1531.         putc(*p++, f);
  1532.           break;
  1533. #endif
  1534.         }
  1535.       (void) fclose(f);
  1536.       UserReturn(1);
  1537.     }
  1538.     }
  1539.   if (UserStatus() <= 0)
  1540.     Msg(0, "Cannot open \"%s\"", fn);
  1541.   else
  1542.     {
  1543.       switch (dump)
  1544.     {
  1545.     case DUMP_TERMCAP:
  1546.       Msg(0, "Termcap entry written to \"%s\".", fn);
  1547.       break;
  1548.     case DUMP_HARDCOPY:
  1549.       Msg(0, "Screen image %s to \"%s\".",
  1550.           (*mode == 'a') ? "appended" : "written", fn);
  1551.       break;
  1552. #ifdef COPY_PASTE
  1553.     case DUMP_EXCHANGE:
  1554.       Msg(0, "Copybuffer written to \"%s\".", fn);
  1555. #endif
  1556.     }
  1557.     }
  1558. }
  1559.  
  1560. #ifdef COPY_PASTE
  1561.  
  1562. void
  1563. ReadFile()
  1564. {
  1565.   int i, l, size;
  1566.   char fn[1024], c;
  1567.   struct stat stb;
  1568.  
  1569.   sprintf(fn, "%s", BufferFile);
  1570.   debug1("ReadFile(%s)\n", fn);
  1571.   if ((i = secopen(fn, O_RDONLY, 0)) < 0)
  1572.     {
  1573.       Msg(errno, "no %s -- no slurp", fn);
  1574.       return;
  1575.     }
  1576.   if (fstat(i, &stb))
  1577.     {
  1578.       Msg(errno, "no good %s -- no slurp", fn);
  1579.       close(i);
  1580.       return;
  1581.     }
  1582.   size = stb.st_size;
  1583.   if (copybuffer)
  1584.     Free(copybuffer);
  1585.   copylen = 0;
  1586.   if ((copybuffer = malloc(size)) == NULL)
  1587.     {
  1588.       close(i);
  1589.       Msg_nomem;
  1590.       return;
  1591.     }
  1592.   errno = 0;
  1593.   if ((l = read(i, copybuffer, size)) != size)
  1594.     {
  1595.       copylen = (l > 0) ? l : 0;
  1596. #ifdef NETHACK
  1597.       if (nethackflag)
  1598.         Msg(errno, "You choke on your food: %d bytes", copylen);
  1599.       else
  1600. #endif
  1601.       Msg(errno, "Got only %d bytes from %s", copylen, fn);
  1602.       close(i);
  1603.       return;
  1604.     }
  1605.   copylen = l;
  1606.   if (read(i, &c, 1) > 0)
  1607.     Msg(0, "Slurped only %d characters into buffer - try again", copylen);
  1608.   else
  1609.     Msg(0, "Slurped %d characters into buffer", copylen);
  1610.   close(i);
  1611.   return;
  1612. }
  1613.  
  1614. void
  1615. KillBuffers()
  1616. {
  1617.   char fn[1024];
  1618.   sprintf(fn, "%s", BufferFile);
  1619.   errno = 0;
  1620.   if (access(fn, W_OK) == -1)
  1621.     {
  1622.       Msg(errno, "%s not removed", fn);
  1623.       return;
  1624.     }
  1625.   else
  1626.     {
  1627.       unlink(fn);
  1628.       Msg(errno, "%s removed", fn);
  1629.     }
  1630. }
  1631. #endif    /* COPY_PASTE */
  1632.  
  1633. #ifdef USRLIMIT
  1634. CountUsers()
  1635. {
  1636. #ifdef GETUTENT
  1637.   struct utmp *ut, *getutent();
  1638. #else
  1639.   struct utmp utmpbuf;
  1640. #endif
  1641.   int UserCount;
  1642.  
  1643.   debug1("CountUsers() - utmp=%d\n",utmp);
  1644.   if (!utmp)
  1645.     return(0);
  1646.   UserCount = 0;
  1647. #ifdef GETUTENT
  1648.   setutent();
  1649.   while (ut = getutent())
  1650.     if (ut->ut_type == USER_PROCESS)
  1651.       UserCount++;
  1652. #else
  1653.   (void) lseek(utmpf, (off_t) 0, 0);
  1654.   while (read(utmpf, &utmpbuf, sizeof(struct utmp)) > 0)
  1655.     {
  1656.       if (utmpbuf.ut_name[0] != '\0')
  1657.        UserCount++;
  1658.     }
  1659. #endif
  1660.   return(UserCount);
  1661. }
  1662. #endif
  1663.  
  1664. #ifdef UTMPOK
  1665.  
  1666. static slot_t loginslot;
  1667. static struct utmp utmp_logintty;
  1668. #ifdef _SEQUENT_
  1669. static char loginhost[100+1];
  1670. #endif
  1671.  
  1672. void
  1673. InitUtmp()
  1674. {
  1675.   debug("InitUtmp testing...\n");
  1676.   if ((utmpf = open(UtmpName, O_RDWR)) == -1)
  1677.     {
  1678.       if (errno != EACCES)
  1679.     Msg(errno, UtmpName);
  1680.       debug("InitUtmp failed.\n");
  1681.       utmp = 0;
  1682.       return;
  1683.     }
  1684. #ifdef GETUTENT
  1685.   close(utmpf);
  1686.   utmpf= -1;
  1687. #endif
  1688. #ifdef MIPS
  1689.   if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
  1690.     {
  1691.       if (errno != EACCES)
  1692.     Msg(errno, UtmpName);
  1693.       return;
  1694.     }
  1695. #endif
  1696.   utmp = 1;
  1697. #ifndef apollo
  1698.   ReInitUtmp();
  1699. #endif
  1700. }
  1701.  
  1702. void
  1703. ReInitUtmp()
  1704. {
  1705. #ifndef apollo
  1706.   if (!utmp)
  1707.     {
  1708.       debug("Reinitutmp: utmp == 0\n");
  1709.       return;
  1710.     }
  1711. #endif
  1712.   debug("(Re)InitUtmp: removing your logintty\n");
  1713.   loginslot = TtyNameSlot(display_tty);
  1714.   if (loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
  1715.     {
  1716. #ifdef _SEQUENT_
  1717.       if (p=ut_find_host(loginslot))
  1718.         strncpy(loginhost, p, 100);
  1719. #endif
  1720.       RemoveLoginSlot(loginslot, &utmp_logintty);
  1721.     }
  1722.   debug1(" slot %d zapped\n", loginslot);
  1723. }
  1724.  
  1725. void
  1726. RestoreLoginSlot()
  1727. {
  1728.   debug("RestoreLoginSlot()\n");
  1729. #ifdef apollo
  1730.   InitUtmp();
  1731. #endif
  1732.   if (utmp && loginslot!=(slot_t)0 && loginslot!=(slot_t)-1)
  1733.     {
  1734. #ifdef GETUTENT
  1735. # ifdef _SEQUENT_
  1736.       int fail;
  1737.       debug1(" logging you in again (slot %s)\n", loginslot);
  1738. /*
  1739.  * We have problems if we add the console and use ut_add_user()
  1740.  * because the id will be 'scon' instead of 'co'. So we
  1741.  * restore it with pututline(). The reason why we don't use
  1742.  * pututline all the time is that we want to set the host field.
  1743.  * Unfortunatelly this can only be done with ut_add_user().
  1744.  */
  1745.       if (*loginhost)
  1746.         {
  1747.           fail = (ut_add_user(LoginName, loginslot, utmp_logintty.ut_pid,
  1748.                               *loginhost?loginhost:(char *)0) == 0);
  1749.         }
  1750.       else
  1751.         {
  1752.           setutent();
  1753.           fail = (pututline(&utmp_logintty) == 0);
  1754.         }
  1755.       if (fail)
  1756. # else    /* _SEQUENT_ */
  1757.       debug1(" logging you in again (slot %s)\n", loginslot);
  1758.       setutent();
  1759.       if (pututline(&utmp_logintty)==0)
  1760. # endif    /* _SEQUENT */
  1761. #else    /* GETUTENT */
  1762.       debug1(" logging you in again (slot %d)\n", loginslot);
  1763. # ifdef sequent
  1764.       /* call sequent undocumented routine to count logins and add utmp entry if possible */
  1765.       if (add_utmp(loginslot, &utmp_logintty) == -1)
  1766. # else
  1767.       (void) lseek(utmpf, (off_t) (loginslot * sizeof(struct utmp)), 0);
  1768.       if (write(utmpf, (char *) &utmp_logintty, sizeof(struct utmp))
  1769.       != sizeof(struct utmp))
  1770. # endif /* sequent */
  1771. #endif    /* GETUTENT */
  1772.         {
  1773. #ifdef NETHACK
  1774.           if (nethackflag)
  1775.             Msg(errno, "%s is too hard to dig in.", UTMPFILE);
  1776.       else
  1777. #endif
  1778.           Msg(errno,"Could not write %s.", UTMPFILE);
  1779.         }
  1780.     }
  1781. #ifdef apollo
  1782.   close(utmpf);
  1783. #endif
  1784.   loginslot = (slot_t) 0;
  1785. }
  1786.  
  1787. void
  1788. RemoveLoginSlot(slot, up)
  1789. slot_t slot;
  1790. struct utmp *up;
  1791. {
  1792. #ifdef GETUTENT
  1793.   struct utmp *uu;
  1794. #endif
  1795.   struct utmp u;
  1796. #ifdef apollo
  1797.   struct utmp *uq;
  1798. #endif
  1799.  
  1800. #ifdef GETUTENT
  1801.   debug2("RemoveLoginSlot(%s, %08x)\n", (slot == (slot_t) 0 ||
  1802.          slot == (slot_t) -1 ) ? "no slot" : slot, up);
  1803. #else
  1804.   debug2("RemoveLoginSlot(%d, %08x)\n", slot, up);
  1805. #endif
  1806. #ifdef apollo
  1807.   InitUtmp();
  1808.   bzero((char *)up, sizeof(struct utmp));
  1809.   uq = (struct utmp *)malloc(sizeof(struct utmp));
  1810.   bzero((char *)uq, sizeof(struct utmp));
  1811. #endif /* apollo */
  1812.   if (!utmp)
  1813.     return;
  1814.   if (slot != (slot_t) 0 && slot != (slot_t) -1)
  1815.     {
  1816.       bzero((char *) &u, sizeof u);
  1817. #ifdef GETUTENT
  1818.       setutent();
  1819.       strncpy(u.ut_line, slot, sizeof(u.ut_line));
  1820.       if ((uu = getutline(&u)) == 0)
  1821.         {
  1822.       DeadlyMsg = 0;
  1823.           Msg(0, "Utmp slot not found -> not removed");
  1824.           return;
  1825.         }
  1826.       *up= *uu;
  1827. # ifdef _SEQUENT_
  1828.       if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
  1829. # else
  1830.       uu->ut_type = DEAD_PROCESS;
  1831.       uu->ut_exit.e_termination = 0;
  1832.       uu->ut_exit.e_exit= 0;
  1833.       if (pututline(uu) == 0)
  1834. # endif
  1835. #else
  1836.       (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  1837.       if (read(utmpf, (char *) up, sizeof u) != sizeof u)
  1838.     {
  1839.       DeadlyMsg = 0;
  1840.       Msg(errno, "cannot read %s ???", UTMPFILE);
  1841.       sleep(1);
  1842.     }
  1843.       (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  1844. # ifdef apollo
  1845.       bcopy((char *)up, (char *)uq, sizeof(struct utmp));
  1846.       bzero(uq->ut_name, sizeof(uq->ut_name));
  1847.       bzero(uq->ut_host, sizeof(uq->ut_host));
  1848.       if (write(utmpf, (char *)uq, sizeof(struct utmp)) != sizeof(struct utmp))
  1849. # else
  1850.       if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  1851. # endif /* apollo */
  1852. #endif
  1853.         {
  1854. #ifdef NETHACK
  1855.           if (nethackflag)
  1856.         {
  1857.           DeadlyMsg = 0;
  1858.               Msg(errno, "%s is too hard to dig in.", UTMPFILE); 
  1859.         }
  1860.           else
  1861. #endif
  1862.         {
  1863.           DeadlyMsg = 0;
  1864.               Msg(errno, "Could not write %s.", UTMPFILE);
  1865.         }
  1866.         }
  1867.     }
  1868.   else 
  1869.     {
  1870.       debug1("There is no utmp-slot to be removed(%d)\n", slot);
  1871.     }
  1872. #ifdef apollo
  1873.   close(utmpf);
  1874.   free(uq);
  1875. #endif
  1876. }
  1877.  
  1878. static slot_t TtyNameSlot(nam)
  1879. char *nam;
  1880. {
  1881.   char *name;
  1882.   register slot_t slot;
  1883. #ifndef GETUTENT
  1884.   register struct ttyent *tp;
  1885. #endif
  1886. #ifdef apollo
  1887.   struct utmp *up;
  1888. #endif
  1889.  
  1890.   debug1("TtyNameSlot(%s)\n", nam);
  1891. #ifdef apollo
  1892.   InitUtmp();
  1893. #endif
  1894.   if (!utmp || nam == NULL)
  1895.     return (slot_t)0;
  1896.   name = stripdev(nam);
  1897. #ifdef GETUTENT
  1898.   slot = name;
  1899. #else
  1900. # ifdef apollo
  1901.   slot = 0;
  1902.   up = (struct utmp *)malloc(sizeof(struct utmp));
  1903.   while (1)
  1904.     {
  1905.       if ((read(utmpf, (char *)up, sizeof(struct utmp)) ==
  1906.        sizeof(struct utmp)) && (strcmp(up->ut_line, name)))
  1907.     slot++;
  1908.       else
  1909.     break;
  1910.     }
  1911.   close(utmpf);
  1912.   free(up);
  1913. # else /* !apollo */
  1914.   slot = 1;
  1915.   setttyent();
  1916.   while ((tp = getttyent()) != NULL && strcmp(name, tp->ty_name) != 0)
  1917.     {
  1918.       debug2("'%s' %d, ", tp->ty_name, slot);
  1919.       ++slot;
  1920.     }
  1921.   debug("\n");
  1922. #  ifdef MIPS
  1923.   if (tp == NULL)
  1924.     {
  1925.       slot = CreateUtmp(name);
  1926.     }
  1927. #  endif /* MIPS */
  1928. # endif /* apollo */
  1929. #endif /* GETUTENT */
  1930.   return slot;
  1931. }
  1932.  
  1933. int
  1934. SetUtmp(wi, displaynumber)
  1935. struct win *wi;
  1936. int displaynumber;
  1937. {
  1938.   register char *p;
  1939.   register slot_t slot;
  1940.   char *line;
  1941.   struct utmp u;
  1942. #ifdef UTHOST
  1943. # ifdef _SEQUENT_
  1944.   char host[100+5];
  1945. # else
  1946.   char host[sizeof(utmp_logintty.ut_host)+5];
  1947. # endif
  1948. #endif
  1949.  
  1950.   wi->slot = (slot_t) 0;
  1951.   if (!utmp)
  1952.     return -1;
  1953.   if ((slot = TtyNameSlot(wi->tty)) == (slot_t) NULL)
  1954.     {
  1955.       debug1("SetUtmp failed (tty %s).\n",wi->tty);
  1956.       return -1;
  1957.     }
  1958.   debug2("SetUtmp %d will get slot %d...\n", displaynumber, (int)slot);
  1959. #ifdef apollo
  1960.   InitUtmp();
  1961. #endif
  1962.  
  1963. #ifdef UTHOST
  1964.   host[sizeof(host)-5] = '\0';
  1965. # ifdef _SEQUENT_
  1966.   strncpy(host, loginhost, sizeof(host) - 5);
  1967. # else
  1968.   strncpy(host, utmp_logintty.ut_host, sizeof(host) - 5);
  1969. # endif
  1970.   if (loginslot != (slot_t)0 && loginslot != (slot_t)-1 && host[0] != '\0')
  1971.     {
  1972.       /*
  1973.        * we want to set our ut_host field to something like
  1974.        * ":ttyhf:s.0" or
  1975.        * "faui45:s.0" or
  1976.        * "132.199.81.4:s.0" (even this may hurt..), but not
  1977.        * "faui45.informati"......:s.0
  1978.        */
  1979.       for (p = host; *p; p++)
  1980.     {
  1981.       if ((*p < '0' || *p > '9') && (*p != '.'))
  1982.         break;
  1983.     }
  1984.       if (*p)
  1985.     {
  1986.       for (p = host; *p; p++)
  1987.         {
  1988.           if (*p == '.')
  1989.         {
  1990.           *p = '\0';
  1991.           break;
  1992.         }
  1993.         }
  1994.     }
  1995.     }
  1996.   else
  1997.     {
  1998.       strncpy(host + 1, stripdev(display_tty), sizeof(host) - 6);
  1999.       host[0] = ':';
  2000.     }
  2001.   debug1("rlogin hostname: '%s'\n", host);
  2002.   sprintf(host + strlen(host), ":S.%c", '0' + displaynumber);
  2003.   debug1("rlogin hostname: '%s'\n", host);
  2004. #endif /* UTHOST */
  2005.  
  2006.   line = stripdev(wi->tty);
  2007.   bzero((char *) &u, sizeof u);
  2008.  
  2009. #ifdef GETUTENT
  2010. # ifdef _SEQUENT_
  2011.   if (ut_add_user(LoginName, slot, wi->wpid, host)==0)
  2012. # else
  2013.   strncpy(u.ut_user, LoginName, sizeof(u.ut_user));
  2014.   strncpy(u.ut_id, line + strlen(line) - 2, sizeof(u.ut_id));
  2015.   strncpy(u.ut_line, line, sizeof(u.ut_line));
  2016.   u.ut_pid = wi->wpid;
  2017.   u.ut_type = USER_PROCESS;
  2018. #  ifdef SVR4
  2019.     (void) time(&u.ut_tv.tv_sec);
  2020.     u.ut_tv.tv_usec=0;
  2021. #  else
  2022.     (void) time(&u.ut_time);
  2023. #  endif /* SVR4 */
  2024. #  ifdef UTHOST
  2025.   strncpy(u.ut_host, host, sizeof(u.ut_host));
  2026. #  endif /* UTHOST */
  2027.   if (pututline(&u) == 0)
  2028. # endif /* _SEQUENT_ */
  2029. #else    /* GETUTENT */
  2030.   strncpy(u.ut_line, line, sizeof(u.ut_line));
  2031.   strncpy(u.ut_name, LoginName, sizeof(u.ut_name));
  2032. # ifdef UTHOST
  2033.   strncpy(u.ut_host, host, sizeof(u.ut_host));
  2034. # endif    /* UTHOST */
  2035. # ifdef MIPS
  2036.   u.ut_type = 7; /* USER_PROCESS */
  2037.   strncpy(u.ut_id, line + 3, 4);
  2038. # endif /* MIPS */
  2039.   (void) time(&u.ut_time);
  2040. # ifdef sequent
  2041. /* call sequent undocumented routine to count logins and add utmp entry if possible */
  2042.   if (add_utmp(slot, &u) == -1)
  2043. # else
  2044.   (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  2045.   if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  2046. # endif /* sequent */
  2047. #endif    /* GETUTENT */
  2048.  
  2049.     {
  2050. #ifdef NETHACK
  2051.       if (nethackflag)
  2052.         Msg(errno, "%s is too hard to dig in.", UTMPFILE);
  2053.       else
  2054. #endif
  2055.       Msg(errno,"Could not write %s.", UTMPFILE);
  2056. #ifdef apollo
  2057.       close(utmpf);
  2058. #endif
  2059.       return -1;
  2060.     }
  2061.   debug("SetUtmp successful\n");
  2062.   wi->slot = slot;
  2063. #ifdef apollo
  2064.   close(utmpf);
  2065. #endif
  2066.   return 0;
  2067. }
  2068.  
  2069. #ifdef MIPS
  2070.  
  2071. #define GETTTYENT
  2072. static int ttyfd = 0;
  2073.  
  2074. static void setttyent()
  2075. {
  2076.   if (ttyfd)
  2077.     close(ttyfd);
  2078.   ttyfd = open(UtmpName, O_RDONLY);
  2079. }
  2080.  
  2081. static struct ttyent *getttyent()
  2082. {
  2083.   static struct utmp u;
  2084.   static struct ttyent t;
  2085.  
  2086.   if (!ttyfd)
  2087.     return NULL;
  2088.   
  2089.   if (read(ttyfd, &u, sizeof u)) 
  2090.     {
  2091.       t.ty_name = u.ut_line;
  2092.       return &t;
  2093.     }
  2094.   return NULL;
  2095. }
  2096.  
  2097. CreateUtmp(name)
  2098. char *name;
  2099. {
  2100.   int slot;
  2101.   struct utmp u;
  2102.  
  2103.   strncpy(u.ut_line, name, 8);
  2104.   strncpy(u.ut_name, LoginName, 8);
  2105.   u.ut_type = 7; /* USER_PROCESS */
  2106.   strncpy(u.ut_id, name+3, 4);
  2107.   (void) time(&u.ut_time);
  2108.   slot = (lseek(utmpfappend, 0, 2) + 1) / sizeof u;
  2109.   (void) write(utmpfappend, (char *)&u, sizeof u);
  2110.   close(utmpfappend);
  2111.   if ((utmpfappend = open(UtmpName, O_APPEND)) == -1) 
  2112.     {
  2113.       if (errno != EACCES)
  2114.         Msg(errno, UtmpName);
  2115.       return;
  2116.     }
  2117.   return slot;
  2118. }
  2119. #endif /* MIPS */
  2120.  
  2121. /*
  2122.  * if slot could be removed or was 0,  wi->slot = -1;
  2123.  * else not changed.
  2124.  */
  2125. int
  2126. RemoveUtmp(wi)
  2127. struct win *wi;
  2128. {
  2129. #ifdef GETUTENT
  2130.   struct utmp *uu;
  2131. #endif
  2132. #ifdef apollo
  2133.   struct utmp *up;
  2134. #endif
  2135.   struct utmp u;
  2136.   slot_t slot;
  2137.  
  2138.   slot = wi->slot;
  2139. #ifdef GETUTENT
  2140.   debug1("RemoveUtmp(%s)\n", (slot == (slot_t) 0) ?
  2141.          "no slot (0)":((slot == (slot_t) -1) ? "no slot (-1)" : slot));
  2142. #else
  2143.   debug1("RemoveUtmp(wi.slot: %d)\n", slot);
  2144. #endif
  2145. #ifdef apollo
  2146.   InitUtmp();
  2147.   up = (struct utmp *)malloc(sizeof(struct utmp));
  2148.   bzero((char *)up, sizeof(struct utmp));
  2149. #endif /* apollo */
  2150.   if (!utmp)
  2151.     return -1;
  2152.   if (slot == (slot_t) 0 || slot == (slot_t) -1)
  2153.     {
  2154.       debug1("There is no utmp-slot to be removed(%d)\n", slot);
  2155.       wi->slot = (slot_t) -1;
  2156.       return 0;
  2157.     }
  2158.   bzero((char *) &u, sizeof u);
  2159. #ifdef GETUTENT
  2160.   setutent();
  2161.   strncpy(u.ut_line, slot, sizeof(u.ut_line));
  2162.   if ((uu = getutline(&u)) == 0)
  2163.     {
  2164.       Msg(0, "Utmp slot not found -> not removed");
  2165.       return -1;
  2166.     }
  2167. # ifdef _SEQUENT_
  2168.   if (ut_delete_user(slot, uu->ut_pid, 0, 0) == 0)
  2169. # else
  2170.   uu->ut_type = DEAD_PROCESS;
  2171.   uu->ut_exit.e_termination = 0;
  2172.   uu->ut_exit.e_exit= 0;
  2173.   if (pututline(uu) == 0)
  2174. # endif
  2175. #else    /* GETUTENT */
  2176.   (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  2177. # ifdef apollo
  2178.   if (read(utmpf, (char *) up, sizeof u) != sizeof u)
  2179.     {
  2180.       DeadlyMsg = 0;
  2181.       Msg(errno, "cannot read %s?", UTMPFILE);
  2182.       sleep(1);
  2183.     }
  2184.   (void) lseek(utmpf, (off_t) (slot * sizeof u), 0);
  2185.   bzero(up->ut_name, sizeof(u.ut_name));
  2186.   bzero(up->ut_host, sizeof(u.ut_host));
  2187.   if (write(utmpf, (char *)up, sizeof u) != sizeof u)
  2188. # else
  2189.   if (write(utmpf, (char *) &u, sizeof u) != sizeof u)
  2190. # endif /* apollo */
  2191. #endif
  2192.     {
  2193. #ifdef NETHACK
  2194.       if (nethackflag)
  2195.         Msg(errno, "%s is too hard to dig in.", UTMPFILE);
  2196.       else
  2197. #endif
  2198.       Msg(errno,"Could not write %s.", UTMPFILE);
  2199. #ifdef apollo
  2200.       close(utmpf);
  2201.       free(up);
  2202. #endif
  2203.       return -1;
  2204.     }
  2205.   debug("RemoveUtmp successfull\n");
  2206.   wi->slot = (slot_t) -1;
  2207. #ifdef apollo
  2208.   close(utmpf);
  2209.   free(up);
  2210. #endif
  2211.   return 0;
  2212. }
  2213.  
  2214. #endif    /* UTMPOK */
  2215.  
  2216. char *
  2217. stripdev(nam)
  2218. char *nam;
  2219. {
  2220. #ifdef apollo
  2221.   char *p;
  2222.  
  2223.   if (nam == NULL)
  2224.     return NULL;
  2225.   if (p = strstr(nam,"/dev/"))
  2226.     return p + 5;
  2227. #else
  2228.   if (nam == NULL)
  2229.     return NULL;
  2230.   if (strncmp(nam, "/dev/", 5) == 0)
  2231.     return nam + 5;
  2232. #endif
  2233.   return nam;
  2234. }
  2235.  
  2236. #if !defined(GETTTYENT) && !defined(GETUTENT)
  2237.  
  2238. static void setttyent()
  2239. {
  2240.   struct stat s;
  2241.   register int f;
  2242.   register char *p, *ep;
  2243.  
  2244.   if (ttnext)
  2245.     {
  2246.       ttnext = tt;
  2247.       return;
  2248.     }
  2249.   if ((f = open(ttys, O_RDONLY)) == -1 || fstat(f, &s) == -1)
  2250.     Msg(errno, ttys);
  2251.   if ((tt = malloc((unsigned) s.st_size + 1)) == 0)
  2252.     Msg_nomem;
  2253.   if (read(f, tt, s.st_size) != s.st_size)
  2254.     Msg(errno, ttys);
  2255.   close(f);
  2256.   for (p = tt, ep = p + s.st_size; p < ep; ++p)
  2257.     if (*p == '\n')
  2258.       *p = '\0';
  2259.   *p = '\0';
  2260.   ttnext = tt;
  2261. }
  2262.  
  2263. static struct ttyent *getttyent()
  2264. {
  2265.   static struct ttyent t;
  2266.  
  2267.   if (*ttnext == '\0')
  2268.     return NULL;
  2269.   t.ty_name = ttnext + 2;
  2270.   ttnext += strlen(ttnext) + 1;
  2271.   return &t;
  2272. }
  2273.  
  2274. #endif    /* GETTTYENT */
  2275.  
  2276. /*
  2277.  * (Almost) secure open and fopen... mlschroe.
  2278.  */
  2279.  
  2280. FILE *
  2281. secfopen(name, mode)
  2282. char *name;
  2283. char *mode;
  2284. {
  2285.   FILE *fi;
  2286. #ifdef NOREUID
  2287.   int flags, fd;
  2288. #endif
  2289.  
  2290.   debug2("secfopen(%s, %s)\n", name, mode);
  2291.   if (eff_uid == real_uid)
  2292.     return(fopen(name, mode));
  2293. #ifndef NOREUID
  2294.   setreuid(eff_uid, real_uid);
  2295.   setregid(eff_gid, real_gid);
  2296.   fi = fopen(name, mode);
  2297.   setreuid(real_uid, eff_uid);
  2298.   setregid(real_gid, eff_gid);
  2299. #else
  2300.   if (mode[0] && mode[1] == '+')
  2301.     flags = O_RDWR;
  2302.   else
  2303.     flags = (mode[0] == 'r') ? O_RDONLY : O_WRONLY;
  2304.   if (mode[0] == 'w')
  2305.     flags |= O_CREAT | O_TRUNC;
  2306.   else if (mode[0] == 'a')
  2307.     flags |= O_CREAT | O_APPEND;
  2308.   else if (mode[0] != 'r')
  2309.     {
  2310.       errno = EINVAL;
  2311.       return(0);
  2312.     }
  2313.   if ((fd = secopen(name, flags, 0666)) < 0)
  2314.     return(0);
  2315.   if ((fi = fdopen(fd, mode)) == 0)
  2316.     {
  2317.       close(fd);
  2318.       return(0);
  2319.     }
  2320. #endif
  2321.   return(fi);
  2322. }
  2323.  
  2324.  
  2325. int
  2326. secopen(name, flags, mode)
  2327. char *name;
  2328. int flags;
  2329. int mode;
  2330. {
  2331.   int fd;
  2332. #ifdef NOREUID
  2333.   int q;
  2334.   struct stat stb;
  2335. #endif
  2336.  
  2337.   debug3("secopen(%s, 0x%x, 0%03o)\n", name, flags, mode);
  2338.   if (eff_uid == real_uid)
  2339.     return(open(name, flags, mode));
  2340. #ifndef NOREUID
  2341.   setreuid(eff_uid, real_uid);
  2342.   setregid(eff_gid, real_gid);
  2343.   fd = open(name, flags, mode);
  2344.   setreuid(real_uid, eff_uid);
  2345.   setregid(real_gid, eff_gid);
  2346. #else
  2347.   /* Truncation/creation is done in UserContext */
  2348.   if ((flags & O_TRUNC) || ((flags & O_CREAT) && access(name, F_OK)))
  2349.     {
  2350.       if (UserContext() > 0)
  2351.     {
  2352.           if ((fd = open(name, flags, mode)) >= 0)
  2353.         {
  2354.           close(fd);
  2355.           UserReturn(0);
  2356.             }
  2357.       if (errno == 0)
  2358.         errno = EACCES;
  2359.       UserReturn(errno);
  2360.     }
  2361.       if (q = UserStatus())
  2362.     {
  2363.       if (q > 0)
  2364.         errno = q;
  2365.           return(-1);
  2366.     }
  2367.     }
  2368.   if (access(name, F_OK))
  2369.     return(-1);
  2370.   if ((fd = open(name, flags & ~(O_TRUNC | O_CREAT), 0)) < 0)
  2371.     return(-1);
  2372.   debug("open successful\n");
  2373.   if (fstat(fd, &stb))
  2374.     {
  2375.       close(fd);
  2376.       return(-1);
  2377.     }
  2378.   debug("fstat successful\n");
  2379.   if (stb.st_uid != real_uid)
  2380.     {
  2381.       switch (flags & (O_RDONLY | O_WRONLY | O_RDWR))
  2382.         {
  2383.     case O_RDONLY:
  2384.       q = 0004;
  2385.       break;
  2386.     case O_WRONLY:
  2387.       q = 0002;
  2388.       break;
  2389.     default:
  2390.       q = 0006;
  2391.       break;
  2392.         }
  2393.       if ((stb.st_mode & q) != q)
  2394.     {
  2395.           debug("secopen: permission denied\n");
  2396.       close(fd);
  2397.       errno = EACCES;
  2398.       return(-1);
  2399.     }
  2400.     }
  2401. #endif
  2402.   debug1("secopen ok - returning %d\n", fd);
  2403.   return(fd);
  2404. }
  2405.  
  2406. #if defined(BUGGYGETLOGIN) && defined(UTMPOK)
  2407. char *
  2408. getlogin()
  2409. {
  2410.   char *tty;
  2411. #ifdef utmp
  2412. # undef utmp
  2413. #endif
  2414.   struct utmp u;
  2415.   static char retbuf[sizeof(u.ut_user)+1];
  2416.   int fd;
  2417.  
  2418.   for (fd = 0; fd <= 2 && (tty = ttyname(fd)) == NULL; fd++)
  2419.     ;
  2420.   if ((tty == NULL) || ((fd = open(UTMP_FILE, O_RDONLY)) < 0))
  2421.     return NULL;
  2422.   tty = stripdev(tty);
  2423.   retbuf[0] = '\0';
  2424.   while (read(fd, &u, sizeof(struct utmp)) == sizeof(struct utmp))
  2425.     {
  2426.       if (!strncmp(tty, u.ut_line, sizeof(u.ut_line)))
  2427.     {
  2428.       strncpy(retbuf, u.ut_user, sizeof(u.ut_user));
  2429.       retbuf[sizeof(u.ut_user)] = '\0';
  2430.       if (u.ut_type == USER_PROCESS)
  2431.         break;
  2432.     }
  2433.     }
  2434.   close(fd);
  2435.  
  2436.   return *retbuf ? retbuf : NULL;
  2437. }
  2438. #endif
  2439.